export const get = (obj, path, fallbackValue) => {
  if (!obj) return fallbackValue

  const nodes = path.split('.')
  const nodesMaxIndex = nodes.length - 1
  const lastChildKey = nodes[nodesMaxIndex]
  const nodesWithoutLastChild = nodes.slice(0, nodesMaxIndex)
  let fatherNode = obj
  for (const i in nodesWithoutLastChild) {
    const childNodeKey = nodesWithoutLastChild[i]
    const childNode = fatherNode[childNodeKey]
    if (!isAvailable(childNode)) {
      return fallbackValue
    }
    fatherNode = childNode
  }

  if (lastChildKey in fatherNode) { return fatherNode[lastChildKey] }

  return fallbackValue
}

export const value = (obj, path, defaultValue) => {
  return get(obj, path, null) ?? defaultValue
}

export const last = (arr) => {
  if (!isArray(arr)) return undefined
  if (!atLeastN(arr, 1)) return null
  return arr[arr.length - 1]
}

export const isObject = (obj) => {
  return Object.prototype.toString.call(obj) === '[object Object]'
}

export const isArray = (arr) => {
  return Object.prototype.toString.call(arr) === '[object Array]'
}

export const isBool = (bool) => {
  return Object.prototype.toString.call(bool) === '[object Boolean]'
}

export const isNumber = (num) => {
  return Object.prototype.toString.call(num) === '[object Number]'
}

export const isNull = (variable) => {
  return Object.prototype.toString.call(variable) === '[object Null]'
}

export const isUndefined = (variable) => {
  return Object.prototype.toString.call(variable) === '[object Undefined]'
}

export const isAvailable = (obj) => {
  return !isUndefined(obj) && !isNull(obj)
}

export const isString = (str) => {
  return Object.prototype.toString.call(str) === '[object String]'
}

// 判断是否为空，可以是字符串，数组，对象
export const isNotBlank = (data) => {
  const t = Object.prototype.toString.call(data)

  switch(t){
    case '[object Object]':
      return Reflect.ownKeys(data).length > 0

    case '[object Array]':
      return data.length > 0

    case '[object String]':
      return data.trim() !== ''

    default:
      return false
  }
}

export const atLeastN = (arr, n) => {
  return isArray(arr) && arr.length >= n
}

export const safeParseInt = (obj,path,fallback) => {
  return parseInt(value(obj,path,null)) || fallback
}

export const safeParseFloat = (obj,path,fallback) => {
  return parseFloat(value(obj,path,null)) || fallback
}

export const atLeast = (obj, keys) => {
  if (!isObject(obj)) { return false }

  if (isString(keys)) { return Object.keys(obj).indexOf(keys) !== -1 }

  if (isArray(keys)) {
    const objKeys = Object.keys(obj)
    let isExists = true
    for (const key of keys) {
      isExists = objKeys.indexOf(key) !== -1
      if (!isExists) return false
    }
    return true
  }
  return false
}

export const isTypeEqual = (targetVar, sourceVar) => {
  return Object.prototype.toString.call(targetVar) === Object.prototype.toString.call(sourceVar)
}

export const isArrayEqual = (targetArr, sourceArr) => {
  if (!isTypeEqual(targetArr, sourceArr)) return false
  if (!isArray(targetArr)) return false
  if (targetArr.length !== sourceArr.length) return false

  for (const i in targetArr) {
    if (isObject(targetArr[i])) {
      if (isObjectEqual(targetArr[i], sourceArr[i])) { continue } else { return false }
    }
    // console.log('kris-debugging',i)
    if (isArray(targetArr[i])) {
      if (isArrayEqual(targetArr[i], sourceArr[i])) { continue } else { return false }
    }

    if (targetArr[i] !== sourceArr[i]) return false
  }

  return true
}

export const isObjectEqual = (targetObj, sourceObj) => {
  if (targetObj === sourceObj) return true

  const targetObjKeys = Object.keys(targetObj)
  const sourceObjKeys = Object.keys(sourceObj)
  if (targetObjKeys.length !== sourceObjKeys.length) return false

  for (const key of targetObjKeys) {
    if (sourceObjKeys.indexOf(key) === -1) return false
  }

  for (const key of targetObjKeys) {
    const tov = targetObj[key]
    const sov = sourceObj[key]

    if (!isTypeEqual(tov, sov)) return false

    if (isObject(tov)) {
      if (isObjectEqual(tov, sov)) {
        continue
      } else {
        return false
      }
    }

    if (isArray(tov)) {
      if (isArrayEqual(tov, sov)) {
        continue
      } else {
        return false
      }
    }

    if (tov !== sov) {
      return false
    }
  }
  return true
}

export function makeQueryParams(queryParams) {
  let query = ''
  const keys = Object.keys(queryParams)

  query = keys
    .filter(key => isAvailable(queryParams[key]))
    .map(key => `${key}=${queryParams[key]}`)
    .join('&')

  return query ? `?${query}` : query
}

export function makeQueryParamsSafe(data) {
  if (data instanceof Object) {
    return makeQueryParams(data)
  }

  return ''
}

export function recursiveSearch(items, key, childrenKey, value, path = []) {
  // debugger
  if (!Array.isArray(items) || items.length <= 0) {
    return null;
  }

  const len = items.length;
  for (let i = 0; i < len; i++) {
    const item = items[i];
    const tempPath = [...path, i];

    if (item[key] === value) {
      return tempPath;
    }

    if (atLeastN(item[childrenKey],1)) {
      let result = recursiveSearch(
        item[childrenKey], 
        key, 
        childrenKey, 
        value, 
        [...tempPath]
      )
      
      if(atLeastN(result,1))
        return result
    }
  }

  return null;
}

export function access(items, childrenKey, path) {
  let children = items
  const pathLen = path.length
  const pathWithoutLastChild = path.slice(0, pathLen - 1)
  const lastChild = path[pathLen - 1]

  for (const i of pathWithoutLastChild) {
    children = children[i][childrenKey]
  }
  return children[lastChild]
}

export function path(items, childrenKey, path) {
  let children = items
  const pathLen = path.length
  const pathWithoutLastChild = path.slice(0, pathLen - 1)
  const lastChild = path[pathLen - 1]
  const result = []

  for (const i of pathWithoutLastChild) {
    result.push(children[i])
    children = children[i][childrenKey]
  }

  result.push(children[lastChild])

  return result
}
